use strict;
use warnings;

use Arcos::Test::Script;
use Arcos::Conf qw(ArcosRoot);
use Arcos::Test;
use Arcos::TestData;
use Arcos::JobQueue;
use Arcos::DB::Job qw($STATUS_COMPLETE);
use File::Spec::Functions qw(catdir catfile splitdir rel2abs canonpath);
use Test::More;
use File::Temp qw(tempfile);

Arcos::Test->plan_if_queued_stopped(tests => 10);

our $MAX_SECONDS   = 20;
our $MAIL_TEMPLATE = <<END_TMPL;
<tmpl_var amount>
<tmpl_var first_name>
<tmpl_var last_name>
END_TMPL
our $MAIL_TEST_ADDRESS = 'dev_null@plusthree.com';

my $cmd = catdir(ArcosRoot(), 'bin', 'arcos_queue_ctl');

my $rc = system($cmd, 'start');
is($rc, 0, 'arcos_queue_ctl started up');

$rc = system($cmd, 'stop');
is($rc, 0, 'arcos_queue_ctl stopped');

my $creator = Arcos::TestData->new();
END { $creator->cleanup() if $creator }

my ($account) =
  $creator->create_payment_account(payment_processor => 'AuthorizeNet',
                                   login             => 'cnpdev2727',
                                   password          => 'lemons!');

# set up a contribution to process
my $contact_info = $creator->create_contact_info(email => $MAIL_TEST_ADDRESS);
my $contribution =
  $creator->create_contribution(payment_account => $account,
                                contact_info    => $contact_info);

# write out script into a temp file
my ($fh, $filename) =
  tempfile(DIR     => catdir(ArcosRoot, 'tmp'),
           CLEANUP => 1);
print $fh $MAIL_TEMPLATE;
close $fh;

my $job_id =
  Arcos::JobQueue->submit_job(type       => 'contribution',
                              parameters => {
                                       contribution_id => $contribution->id(),
                                       email_template  => $filename
                              });

system($cmd, 'start');

my $timer = 0;
while ($timer < $MAX_SECONDS) {
    if (Arcos::JobQueue->is_complete($job_id)) { last }
    sleep 1;
    $timer++;
}
if ($timer == $MAX_SECONDS) {
    fail("job did not complete in $MAX_SECONDS seconds");
} else {
    pass('job is complete');
}
is( Arcos::JobQueue->get_result($job_id)->{'success'},
    1, 'results contain correct values');

# now make sure a job with a bad mapping doesn't crash the daemon
eval { Arcos::JobQueue->submit_job(type => 'bogus', parameters => {}); };
like($@, qr/Invalid job type/, 'invalid job caught by submit_job');

system($cmd, 'stop');

# start up the job-queue processing all jobs except contributions
system($cmd . ' --exclude-type contribution start');

my $ignore_contribution =
  $creator->create_contribution(payment_account => $account,
                                contact_info    => $contact_info);

my $ignore_job_id =
  Arcos::JobQueue->submit_job(
                            type       => 'contribution',
                            parameters => {
                                contribution_id => $ignore_contribution->id(),
                                email_template  => $filename
                            });

# wait a little while to see that it's not processed
$timer = 0;
while ($timer < int($MAX_SECONDS / 2)) {
    if (Arcos::JobQueue->is_complete($ignore_job_id)) { last }
    sleep 1;
    $timer++;
}
if ($timer == int($MAX_SECONDS / 2)) {
    pass("job was ignored for $MAX_SECONDS seconds by --exclude-type");
} else {
    fail('job completed despite --exclude-type');
}

system($cmd, 'stop');

# start up the job-queue processing just contributions
system($cmd . ' --type contribution start');

# wait a little while to see that it's processed
$timer = 0;
while ($timer < $MAX_SECONDS) {
    if (Arcos::JobQueue->is_complete($ignore_job_id)) { last }
    sleep 1;
    $timer++;
}
if ($timer == $MAX_SECONDS) {
    fail("job did not complete in $MAX_SECONDS seconds");
} else {
    pass('job is complete');
}
is( Arcos::JobQueue->get_result($ignore_job_id)->{'success'},
    1, 'results contain correct values');

Arcos::DB::Job->retrieve($job_id)->delete();
Arcos::DB::Job->retrieve($ignore_job_id)->delete();

system($cmd, 'stop');

# test for failed status by creating an invalid job
{
    my $job_id =
      Arcos::JobQueue->submit_job(type       => 'contribution',
                                  parameters => { invalid => 1 });
    system($cmd, 'start');

    my $timer = 0;
    while ($timer < $MAX_SECONDS) {
        if (Arcos::JobQueue->is_complete($job_id)) { last }
        sleep 1;
        $timer++;
    }
    if ($timer == $MAX_SECONDS) {
        fail("job did not complete in $MAX_SECONDS seconds");
    } else {
        pass('job is complete');
    }

    my $job = Arcos::DB::Job->retrieve($job_id);
    END { $job->delete if $job }
    is( $job->status, 'failed', 'job has failed status');

    system($cmd, 'stop');
}
